package com.smasher.bluetooth.fragment;


import static android.app.Activity.RESULT_OK;

import android.Manifest;
import android.annotation.SuppressLint;
import android.app.Dialog;
import android.bluetooth.BluetoothDevice;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.widget.Toast;

import androidx.activity.result.ActivityResult;
import androidx.activity.result.ActivityResultCallback;
import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import androidx.annotation.RequiresPermission;
import androidx.core.content.ContextCompat;
import androidx.fragment.app.DialogFragment;
import androidx.recyclerview.widget.LinearLayoutManager;

import com.smasher.bluetooth.databinding.FragmentDevicesBinding;
import com.smasher.bluetooth.scan.BaseDiscovering;
import com.smasher.bluetooth.scan.DeviceFoundListener;
import com.smasher.bluetooth.scan.DiscoveringBle;
import com.smasher.bluetooth.scan.DiscoveringClassic;
import com.smasher.decoration.group.GroupSwordDecoration;
import com.smasher.widget.listener.OnItemClickListener;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Set;

public class DeviceSelector extends DialogFragment {

    public static final String TAG = "DeviceSelector";

    private final List<BluetoothDevice> mDeviceList = new ArrayList<>();
    private final List<BluetoothDevice> mPairedList = new ArrayList<>();
    private DeviceAdapter mDeviceArrayAdapter;


    private OnSelectListener mOnSelectListener;
    private FragmentDevicesBinding mBinding;
    private BaseDiscovering mDiscovering;

    private boolean hasPermission = false;


    private final String[] permissions = new String[]{
            Manifest.permission.BLUETOOTH,
            Manifest.permission.BLUETOOTH_ADMIN,
            Manifest.permission.ACCESS_FINE_LOCATION,
            Manifest.permission.ACCESS_COARSE_LOCATION
    };

    @RequiresApi(api = Build.VERSION_CODES.S)
    private final String[] permission30above = new String[]{
            Manifest.permission.BLUETOOTH_SCAN,
            Manifest.permission.BLUETOOTH_CONNECT,
            Manifest.permission.BLUETOOTH_ADVERTISE
    };


    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mDeviceArrayAdapter = new DeviceAdapter();
        mDiscovering = new DiscoveringBle(requireContext());
        mDiscovering.init(requireContext());
        mDiscovering.setDeviceFoundListener(new DeviceFoundListener() {
            @RequiresPermission(Manifest.permission.BLUETOOTH_CONNECT)
            @Override
            public void onDeviceFound(BluetoothDevice device) {
                String name = device.getName();
                if (name != null) {
                    addDeviceToList(device);
                }
            }
        });

        checkBluetoothPermission();
    }

    @SuppressLint("NotifyDataSetChanged")
    private void addDeviceToList(BluetoothDevice device) {
        if (device == null) {
            return;
        }
        boolean isExist = false;
        String address = device.getAddress();
        for (BluetoothDevice bean : mDeviceList) {
            if (address.equals(bean.getAddress())) {
                isExist = true;
                break;
            }
        }
        if (!isExist) {
            mDeviceList.add(device);
            mDeviceArrayAdapter.notifyDataSetChanged();
        }
    }

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        mBinding = FragmentDevicesBinding.inflate(inflater, container, false);
        return mBinding.getRoot();
    }

    @Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);

        mDeviceArrayAdapter.setOnItemClickListener(mOnItemClickListener);
        mDeviceArrayAdapter.setData(mDeviceList);

        mBinding.toolbar.setNavigationOnClickListener(v -> dismiss());
        mBinding.refreshLayout.setOnRefreshListener(refreshLayout -> {
            refreshLayout.finishRefresh(2000);
        });

        mBinding.recyclerview.setAdapter(mDeviceArrayAdapter);
        mBinding.recyclerview.addItemDecoration(new GroupSwordDecoration(requireContext()));
        mBinding.recyclerview.setLayoutManager(new LinearLayoutManager(requireContext(), LinearLayoutManager.VERTICAL, false));
    }

    @Override
    public void onStart() {
        super.onStart();
        Dialog dialog = getDialog();

        if (dialog != null) {
            Window window = dialog.getWindow();
            if (window != null) {
                window.setLayout(getWidth(), getHeight());
            }
        }
    }

    @Override
    public void onResume() {
        super.onResume();
    }

    private void checkBluetoothPermission() {
        String[] bluetoothPermissions = Build.VERSION.SDK_INT > Build.VERSION_CODES.R ? permission30above : permissions;
        boolean isAllGranted = true;
        for (String permission : bluetoothPermissions) {
            int result = ContextCompat.checkSelfPermission(requireContext(), permission);
            if (result != PackageManager.PERMISSION_GRANTED) {
                isAllGranted = false;
            }
            boolean logResult = result == PackageManager.PERMISSION_GRANTED;
            Log.e(TAG, "checkBluetoothPermission: " + permission + "-result=" + logResult);
        }
        if (!isAllGranted) {
            hasPermission = false;
            requestPermission();
        } else {
            hasPermission = true;
            startBlueAction();
        }
    }

    @RequiresPermission(allOf = {Manifest.permission.BLUETOOTH_SCAN, Manifest.permission.BLUETOOTH_CONNECT})
    private void startBlueAction() {
        if (hasPermission) {
            boolean isEnable = mDiscovering.enableBluetooth(requireContext());
            if (isEnable) {
                updatePairedList();
                mDiscovering.startDiscovering();
            } else {
                Intent intent = mDiscovering.createIntentForEnable();
                enableBluetoothLauncher.launch(intent);
            }
        }
    }

    @SuppressLint("NotifyDataSetChanged")
    @RequiresPermission(Manifest.permission.BLUETOOTH_CONNECT)
    private void updatePairedList() {
        mPairedList.clear();
        Set<BluetoothDevice> pairedDevices = mDiscovering.queryRecord();
        mPairedList.addAll(pairedDevices);
        int count=  mPairedList.size();
        mDeviceArrayAdapter.setPairedCount(count);
        mDeviceList.addAll(mPairedList);
        mDeviceArrayAdapter.notifyDataSetChanged();
    }


    private final ActivityResultLauncher<Intent> enableBluetoothLauncher =
            registerForActivityResult(new ActivityResultContracts.StartActivityForResult(),
                    new ActivityResultCallback<>() {

                        @RequiresPermission(allOf = {Manifest.permission.BLUETOOTH_SCAN, Manifest.permission.BLUETOOTH_CONNECT})
                        @Override
                        public void onActivityResult(ActivityResult result) {
                            if (result.getResultCode() == RESULT_OK) {
                                startBlueAction();
                            }
                        }
                    });


    private void requestPermission() {
        String[] bluetoothPermissions = Build.VERSION.SDK_INT > Build.VERSION_CODES.R ? permission30above : permissions;
        Log.e(TAG, "requestPermission: " + Arrays.toString(bluetoothPermissions));
        requestPermissionLauncher.launch(bluetoothPermissions);
    }

    private final ActivityResultLauncher<String[]> requestPermissionLauncher =
            registerForActivityResult(new ActivityResultContracts.RequestMultiplePermissions(), map -> {
                boolean isAllGranted = true;
                for (String key : map.keySet()) {
                    boolean keyValue = Boolean.TRUE.equals(map.get(key));
                    Log.e(TAG, key + ": " + keyValue);
                    if (!keyValue) {
                        isAllGranted = false;
                    }
                }
                afterRequestPermission(isAllGranted);
            });

    @SuppressLint("MissingPermission")
    private void afterRequestPermission(boolean isAllGranted) {
        Log.e(TAG, "afterRequestPermission: " + isAllGranted);
        if (!isAllGranted) {
            hasPermission = false;
            Toast.makeText(requireContext(), "请授予所需的权限", Toast.LENGTH_SHORT).show();
        } else {
            hasPermission = true;
        }
    }


    /**
     * can use{@link ViewGroup.LayoutParams#MATCH_PARENT}
     * or {@link ViewGroup.LayoutParams#WRAP_CONTENT}
     * or exactly number
     */
    protected int getWidth() {
        return ViewGroup.LayoutParams.MATCH_PARENT;
    }

    /**
     * can use{@link ViewGroup.LayoutParams#MATCH_PARENT}
     * or {@link ViewGroup.LayoutParams#WRAP_CONTENT}
     * or exactly number
     */
    protected int getHeight() {
        return ViewGroup.LayoutParams.MATCH_PARENT;
    }

    public void setOnSelectListener(OnSelectListener listener) {
        mOnSelectListener = listener;
    }

    public boolean isShowing() {
        return getDialog() != null && getDialog().isShowing();
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        mDiscovering.release(requireContext());
    }

    private final OnItemClickListener mOnItemClickListener =
            new OnItemClickListener() {
                @Override
                public void onClick(View view, int position) {
                    int len = mDeviceList.size();
                    if (position < 0 || position >= len) {
                        return;
                    }
                    BluetoothDevice device = mDeviceList.get(position);
                    if (mOnSelectListener != null) {
                        mOnSelectListener.onSelect(device);
                    }
                    dismiss();
                }

                @Override
                public void onLongClick(View view, int i) {

                }

                @Override
                public void onEditFinish(View view, int i, String s) {

                }
            };


    public interface OnSelectListener {
        void onSelect(BluetoothDevice device);
    }

    public static DeviceSelector newInstance() {
        Bundle args = new Bundle();
        DeviceSelector fragment = new DeviceSelector();
        fragment.setArguments(args);
        return fragment;
    }
}
